Attribute VB_Name = "HIDModules"
Option Explicit

Public FatalError As String
Public HidDevice As Long
Dim PreparsedData As Long
Public Capabilities As HIDP_CAPS
Dim hEventObject As Long
Dim ReadPending As Boolean
Dim Overlapped As OVER_LAPPED
Dim NumberOfBytesRead As Long
Public ReadBuffer() As Byte
Dim TotalDataLength() As Byte
Dim TotalData() As Byte
Dim TotalLengthRptDataLen As Integer
Dim TotalRptDataLen As Integer
Public FtrRptTrxBfr() As Byte
Public FtrRptRcvBfr() As Byte
Public SendCmdSts As Byte
Public DeviceAttributes As HIDD_ATTRIBUTES
Public security As SECURITY_ATTRIBUTES

Public Const DIGCF_PRESENT = &H2
Public Const DIGCF_DEVICEINTERFACE = &H10
Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Public Const GENERIC_READ = &H80000000
Public Const GENERIC_WRITE = &H40000000
Public Const GENERIC_NOACCESS = 0

Public Const FILE_SHARE_READ = &H1
Public Const FILE_SHARE_WRITE = &H2
Public Const FILE_FLAG_OVERLAPPED = &H40000000
Public Const ERROR_IO_PENDING = 997
Public Const ERROR_IO_INCOMPLETE = 996
Public Const ERROR_INSUFFICIENT_BUFFER = 122
Public Const INVALID_HANDLE_VALUE = &HFFFFFFFF
Public Const HIDP_STATUS_SUCCESS = &H110000

Public Const HidP_Input = 0
Public Const HidP_Output = 1
Public Const HidP_Feature = 2

Public Const OPEN_EXISTING = 3

Public Const IdtVendorID = &HACD
Public Const ProdID = &H2010    ' SecureMag USB HID Reader
Public Const ProdID2 = &H2030   ' SecureMag USB KB Reader
Public Const ProdID3 = &H500      ' MS246 USB HID Reader
Public Const ProdID4 = &H111      ' MS246 USB KB Reader

Public Const UPG_MSR = &HFF00
Public Const UID_DECODING_RDR = &H1
Public Const UID_TRACK_1_DECODE_STATUS = &H20
Public Const UID_TRACK_2_DECODE_STATUS = &H21
Public Const UID_TRACK_3_DECODE_STATUS = &H22
Public Const UID_TRACK_1_LEN = &H28
Public Const UID_TRACK_2_LEN = &H29
Public Const UID_TRACK_3_LEN = &H2A
Public Const UID_TOTAL_DATA_LENGTH = &H30
Public Const UID_TOTAL_DATA = &H31
Public Const UID_CARD_ENCODE_TYPE = &H38

Public Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type

Public Type HIDD_ATTRIBUTES
    Size As Long
    VendorID As Integer
    ProductID As Integer
    VersionNumber As Integer
End Type

Public Type HIDP_CAPS
    Usage As Integer
    UsagePage As Integer
    InputReportByteLength As Integer
    OutputReportByteLength As Integer
    FeatureReportByteLength As Integer
    Reserved(16) As Integer
    NumberLinkCollectionNodes As Integer
    NumberInputButtonCaps As Integer
    NumberInputValueCaps As Integer
    NumberInputDataIndices As Integer
    NumberOutputButtonCaps As Integer
    NumberOutputValueCaps As Integer
    NumberOutputDataIndices As Integer
    NumberFeatureButtonCaps As Integer
    NumberFeatureValueCaps As Integer
    NumberFeatureDataIndices As Integer
End Type

Public Type HIDP_VALUE_CAPS
    UsagePage As Integer
    ReportID As Byte
    BitField As Integer
    LinkCollection As Integer
    LinkUsage As Integer
    LinkUsagePage As Integer
    IsRange As Byte
    IsStringRange As Byte
    IsDesignatorRange As Byte
    IsAbsolute As Byte
    HasNull As Byte
    Reserved1 As Byte
    BitSize As Integer
    ReportCount As Integer
    Reserved2 As Integer
    Reserved3 As Integer
    Reserved4 As Integer
    Reserved5 As Integer
    Reserved6 As Integer
    UnitsExp As Long
    Units As Long
    LogicalMin As Long
    LogicalMax As Long
    PhysicalMin As Long
    PhysicalMax As Long
    UsageMin As Integer
    UsageMax As Integer
    StringMin As Integer
    StringMax As Integer
    DesignatorMin As Integer
    DesignatorMax As Integer
    DataIndexMin As Integer
    DataIndexMax As Integer
End Type

Public Type SP_DEVICE_INTERFACE_DATA
   cbSize As Long
   InterfaceClassGuid As GUID
   Flags As Long
   Reserved As Long
End Type

Public Type SP_DEVICE_INTERFACE_DETAIL_DATA
    cbSize As Long
    DevicePath As Byte
End Type

Public Type OVER_LAPPED
    Internal As Long
    InternalHigh As Long
    Offset As Long
    OffsetHigh As Long
    hEvent As Long
End Type

Public Type SECURITY_ATTRIBUTES
    nLength As Long
    lpSecurityDescriptor As Long
    bInheritHandle As Long
End Type


Public Declare Function CloseHandle _
    Lib "kernel32" _
    (ByVal hObject As Long) _
As Long

Public Declare Function CreateFile _
    Lib "kernel32" _
    Alias "CreateFileA" _
    (ByVal lpFileName As String, _
    ByVal dwDesiredAccess As Long, _
    ByVal dwShareMode As Long, _
    ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
    ByVal dwCreationDisposition As Long, _
    ByVal dwFlagsAndAttributes As Long, _
    ByVal hTemplateFile As Long) _
As Long

Public Declare Function FormatMessage _
    Lib "kernel32" _
    Alias "FormatMessageA" _
    (ByVal dwFlags As Long, _
    ByRef lpSource As Any, _
    ByVal dwMessageId As Long, _
    ByVal dwLanguageZId As Long, _
    ByVal lpBuffer As String, _
    ByVal nSize As Long, _
    ByVal Arguments As Long) _
As Long

Public Declare Function HidD_FreePreparsedData _
    Lib "hid.dll" _
    (ByVal PreparsedData As Long) _
As Long

Public Declare Function HidD_GetAttributes _
    Lib "hid.dll" _
    (ByVal HidDeviceObject As Long, _
    ByRef Attributes As HIDD_ATTRIBUTES) _
As Byte

Public Declare Sub HidD_GetHidGuid _
    Lib "hid.dll" _
    (ByRef HidGuid As GUID)

Public Declare Function HidD_GetPreparsedData _
    Lib "hid.dll" _
    (ByVal HidDeviceObject As Long, _
    ByRef PreparsedData As Long) _
As Byte

Public Declare Function HidP_GetCaps _
    Lib "hid.dll" _
    (ByVal PreparsedData As Long, _
    ByRef Capabilities As HIDP_CAPS) _
As Long

Public Declare Function HidP_GetValueCaps _
    Lib "hid.dll" _
    (ByVal ReportType As Integer, _
    ByRef ValueCaps As HIDP_VALUE_CAPS, _
    ByRef ValueCapsLength As Integer, _
    ByVal PreparsedData As Long) _
As Long

Public Declare Function HidP_GetSpecificValueCaps _
    Lib "hid.dll" _
    (ByVal ReportType As Integer, _
    ByVal UsagePage As Integer, _
    ByVal LinkCollection As Integer, _
    ByVal Usage As Integer, _
    ByRef ValueCaps As HIDP_VALUE_CAPS, _
    ByRef ValueCapsLength As Integer, _
    ByVal PreparsedData As Long) _
As Long

Public Declare Function lstrcpy _
    Lib "kernel32" _
    Alias "lstrcpyA" _
    (ByVal dest As String, _
    ByVal source As Long) _
As String

Public Declare Function lstrlen _
    Lib "kernel32" _
    Alias "lstrlenA" _
    (ByVal source As Long) _
As Long

Public Declare Function ReadFile _
    Lib "kernel32" _
    (ByVal hFile As Long, _
    ByRef lpBuffer As Byte, _
    ByVal nNumberOfBytesToRead As Long, _
    ByRef lpNumberOfBytesRead As Long, _
    ByRef lpOverlapped As OVER_LAPPED) _
As Long

Public Declare Function RtlMoveMemory _
    Lib "kernel32" _
    (dest As Any, _
    src As Any, _
    ByVal Count As Long) _
As Long

Public Declare Function SetupDiCreateDeviceInfoList _
    Lib "setupapi.dll" _
    (ByRef ClassGuid As GUID, _
    ByVal hwndParent As Long) _
As Long

Public Declare Function SetupDiDestroyDeviceInfoList _
    Lib "setupapi.dll" _
    (ByVal DeviceInfoSet As Long) _
As Long

Public Declare Function SetupDiEnumDeviceInterfaces _
    Lib "setupapi.dll" _
    (ByVal DeviceInfoSet As Long, _
    ByVal DeviceInfoData As Long, _
    ByRef InterfaceClassGuid As GUID, _
    ByVal MemberIndex As Long, _
    ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) _
As Long

Public Declare Function SetupDiGetClassDevs _
    Lib "setupapi.dll" _
    Alias "SetupDiGetClassDevsA" _
    (ByRef ClassGuid As GUID, _
    ByVal Enumerator As String, _
    ByVal hwndParent As Long, _
    ByVal Flags As Long) _
As Long

Public Declare Function SetupDiGetDeviceInterfaceDetail _
   Lib "setupapi.dll" _
   Alias "SetupDiGetDeviceInterfaceDetailA" _
   (ByVal DeviceInfoSet As Long, _
   ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
   ByVal DeviceInterfaceDetailData As Long, _
   ByVal DeviceInterfaceDetailDataSize As Long, _
   ByRef RequiredSize As Long, _
   ByVal DeviceInfoData As Long) _
As Long

Public Declare Function WriteFile _
    Lib "kernel32" _
    (ByVal hFile As Long, _
    ByRef lpBuffer As Byte, _
    ByVal nNumberOfBytesToWrite As Long, _
    ByRef lpNumberOfBytesWritten As Long, _
    ByVal lpOverlapped As Long) _
As Long
    
Public Declare Function CancelIo _
    Lib "kernel32" _
    (ByVal hFile As Long) _
As Long

Public Declare Function GetOverlappedResult _
    Lib "kernel32" _
    (ByVal hFile As Long, _
    ByRef lpOverlapped As OVER_LAPPED, _
    ByRef lpNumberOfBytesRead As Long, _
    ByVal bWait As Long) _
As Long

Public Declare Function CreateEvent _
    Lib "kernel32" _
    Alias "CreateEventA" _
    (ByVal lpEventAttributes As Long, _
    ByVal bManualReset As Long, _
    ByVal bInitialState As Long, _
    ByVal lpName As Long) _
As Long
  
Public Declare Function ResetEvent _
    Lib "kernel32" _
    (ByVal hEvent As Long) _
As Long
        
Public Declare Function HidP_GetUsageValue _
    Lib "hid.dll" _
    (ByVal ReportType As Integer, _
    ByVal UsagePage As Integer, _
    ByVal LinkCollection As Integer, _
    ByVal Usage As Integer, _
    ByRef UsageValue As Long, _
    ByVal PreparsedData As Long, _
    ByRef Report As Byte, _
    ByVal ReportLength As Long) _
As Long

Public Declare Function HidP_GetUsageValueArray _
    Lib "hid.dll" _
    (ByVal ReportType As Integer, _
    ByVal UsagePage As Integer, _
    ByVal LinkCollection As Integer, _
    ByVal Usage As Integer, _
    ByRef UsageValue As Byte, _
    ByVal UsageValueByteLength As Integer, _
    ByVal PreparsedData As Long, _
    ByRef Report As Byte, _
    ByVal ReportLength As Long) _
As Long

Public Declare Function HidD_GetFeature _
    Lib "hid.dll" _
    (ByVal HidDeviceObject As Long, _
    ByRef ReportBuffer As Byte, _
    ByVal ReportBufferLength As Long) _
As Byte

Public Declare Function HidD_SetFeature _
    Lib "hid.dll" _
    (ByVal HidDeviceObject As Long, _
    ByRef ReportBuffer As Byte, _
    ByVal ReportBufferLength As Long) _
As Byte

Public Sub DetectDevice()
Dim HidGuid As GUID
Dim DeviceInfoSet As Long
Dim Result As Long
Dim MemberIndex As Long
Dim MyDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
Dim LastDevice As Boolean
Dim RequiredSize As Long
Dim DumRequiredSize As Long
Dim MyDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
Dim DetailDataBuffer() As Byte
Dim DevicePathName As String

Call HidD_GetHidGuid(HidGuid)

DeviceInfoSet = SetupDiGetClassDevs _
    (HidGuid, _
    vbNullString, _
    0, _
    (DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE))
    
If DeviceInfoSet = INVALID_HANDLE_VALUE Then
    Exit Sub
End If

LastDevice = False
MemberIndex = 0
Do
    MyDeviceInterfaceData.cbSize = LenB(MyDeviceInterfaceData)
    Result = SetupDiEnumDeviceInterfaces _
        (DeviceInfoSet, _
        0, _
        HidGuid, _
        MemberIndex, _
        MyDeviceInterfaceData)
    
    If Result = 0 Then
        LastDevice = True
    Else
        Result = SetupDiGetDeviceInterfaceDetail _
           (DeviceInfoSet, _
           MyDeviceInterfaceData, _
           0, _
           0, _
           RequiredSize, _
           0)
        If Result = 0 And Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then
            MyDeviceInterfaceDetailData.cbSize = _
                Len(MyDeviceInterfaceDetailData)
            
            ReDim DetailDataBuffer(RequiredSize)
            
            Call RtlMoveMemory _
                (DetailDataBuffer(0), _
                MyDeviceInterfaceDetailData, _
                4)
            
            Result = SetupDiGetDeviceInterfaceDetail _
               (DeviceInfoSet, _
               MyDeviceInterfaceData, _
               VarPtr(DetailDataBuffer(0)), _
               RequiredSize, _
               DumRequiredSize, _
               0)
                    
            DevicePathName = CStr(DetailDataBuffer())
            DevicePathName = StrConv(DevicePathName, vbUnicode)
            DevicePathName = Right$(DevicePathName, Len(DevicePathName) - 4)

            security.lpSecurityDescriptor = 0
            security.bInheritHandle = True
            security.nLength = Len(security)
        
            HidDevice = CreateFile _
                (DevicePathName, _
                GENERIC_READ Or GENERIC_WRITE, _
                (FILE_SHARE_READ Or FILE_SHARE_WRITE), _
                security, _
                OPEN_EXISTING, _
                FILE_FLAG_OVERLAPPED, _
                0)
    
            If HidDevice = INVALID_HANDLE_VALUE Then
                HidDevice = CreateFile _
                    (DevicePathName, _
                    GENERIC_NOACCESS, _
                    (FILE_SHARE_READ Or FILE_SHARE_WRITE), _
                    security, _
                    OPEN_EXISTING, _
                    FILE_FLAG_OVERLAPPED, _
                    0)
            End If
                       
            
            If HidDevice <> INVALID_HANDLE_VALUE Then
                DeviceAttributes.Size = LenB(DeviceAttributes)
                If HidD_GetAttributes(HidDevice, DeviceAttributes) Then
                    If ((DeviceAttributes.VendorID = IdtVendorID) And _
                    ((DeviceAttributes.ProductID = ProdID) Or _
                    (DeviceAttributes.ProductID = ProdID2) Or _
                    (DeviceAttributes.ProductID = ProdID3) Or _
                    (DeviceAttributes.ProductID = ProdID4))) Then
                        If HidD_GetPreparsedData(HidDevice, PreparsedData) Then
                                Result = HidP_GetCaps _
                                (PreparsedData, _
                                Capabilities)
                                If Result <> HIDP_STATUS_SUCCESS Then
                                    CloseDevice
                                End If
                        Else
                            CloseDevice
                        End If
                    Else
                        CloseDevice
                    End If
                Else
                    CloseDevice
                End If
            End If
        End If
    End If
    MemberIndex = MemberIndex + 1
Loop Until (LastDevice = True) Or (HidDevice <> INVALID_HANDLE_VALUE)

Result = SetupDiDestroyDeviceInfoList _
    (DeviceInfoSet)

End Sub

Public Sub CloseDevice()
    Dim Result As Long
        
    If HidDevice <> INVALID_HANDLE_VALUE Then
        If ReadPending Then
            ReadPending = False
            Result = CancelIo(HidDevice)
        End If
        Result = CloseHandle(HidDevice)
        HidDevice = INVALID_HANDLE_VALUE
    End If
    
    If PreparsedData <> 0 Then
        Result = HidD_FreePreparsedData(PreparsedData)
        PreparsedData = 0
    End If
End Sub

Public Sub InitUSB()
    FatalError = ""
    HidDevice = INVALID_HANDLE_VALUE
    PreparsedData = 0
    hEventObject = CreateEvent(0, 1, 0, 0)
    If hEventObject = 0 Then
        FatalError = "CreateEvent Failed"
    End If
    ReadPending = False
End Sub

Public Sub CloseUSB()
    Dim Result As Long
    
    If hEventObject <> 0 Then
        Result = CloseHandle(hEventObject)
    End If
End Sub

Public Function ReadInputRpt() As Boolean
    Dim Result As Long
    ReadInputRpt = False
    
    If ReadPending Then

        If GetOverlappedResult _
        (HidDevice, _
        Overlapped, _
        NumberOfBytesRead, _
        0) = 0 Then

            If Err.LastDllError <> ERROR_IO_INCOMPLETE Then
                CloseDevice
            End If
        Else
            ReadPending = False
            ReadInputRpt = True
        End If
    Else

        If ResetEvent(hEventObject) = 0 Then
            FatalError = "ResetEvent Failed"
            Exit Function
        End If
        
        Overlapped.hEvent = hEventObject
        Overlapped.Internal = 0
        Overlapped.InternalHigh = 0
        Overlapped.Offset = 0
        Overlapped.OffsetHigh = 0

        If ReadFile _
        (HidDevice, _
        ReadBuffer(0), _
        CLng(Capabilities.InputReportByteLength), _
        NumberOfBytesRead, _
        Overlapped) = 0 Then
            If Err.LastDllError = ERROR_IO_PENDING Then
               ReadPending = True
            Else
                'CloseDevice
            End If
        Else
            ReadInputRpt = True
        End If
    End If
End Function

Public Sub InitRead()

    Dim ValueCaps As HIDP_VALUE_CAPS
    Dim NumberInputValueCaps As Integer
    Dim Result As Long

    ReDim ReadBuffer(Capabilities.InputReportByteLength - 1)

    NumberInputValueCaps = 1
    Result = HidP_GetSpecificValueCaps _
    (HidP_Input, _
    UPG_MSR, _
    0, _
    UID_TOTAL_DATA_LENGTH, _
    ValueCaps, _
    NumberInputValueCaps, _
    PreparsedData)
    If Result <> HIDP_STATUS_SUCCESS Then
        FatalError = Hex(Result) & " HidP_GetSpecificValueCaps Failed on Total Data Length usage"
        Exit Sub
    End If



    NumberInputValueCaps = 1
    If HidP_GetSpecificValueCaps _
    (HidP_Input, _
    UPG_MSR, _
    0, _
    UID_TOTAL_DATA, _
    ValueCaps, _
    NumberInputValueCaps, _
    PreparsedData) <> HIDP_STATUS_SUCCESS Then
        FatalError = "HidP_GetSpecificValueCaps Failed on Total data usage"
        Exit Sub
    End If

End Sub


Public Sub InitCmd()

    ReDim FtrRptTrxBfr(Capabilities.FeatureReportByteLength - 1)
    ReDim FtrRptRcvBfr(Capabilities.FeatureReportByteLength - 1)
    
End Sub

Public Sub SendCmd()
    Dim FtrRptIndex As Long
     
    If HidD_SetFeature _
    (HidDevice, _
    FtrRptTrxBfr(0), _
    Capabilities.FeatureReportByteLength) <> 1 Then
        CloseDevice
        Exit Sub
    End If
End Sub

Public Sub GetResponse()
    Dim FtrRptIndex As Long

    For FtrRptIndex = 1 To Capabilities.FeatureReportByteLength
        FtrRptRcvBfr(FtrRptIndex - 1) = 0
    Next

    If HidD_GetFeature _
    (HidDevice, _
    FtrRptRcvBfr(0), _
    Capabilities.FeatureReportByteLength) <> 1 Then
        CloseDevice
        Exit Sub
    End If
End Sub


